package services.kingdee

import play.api.Logging
import play.api.libs.json.{JsArray, JsValue, Json}
import utiliy.UnitChangePercent

import javax.inject.Inject
import scala.concurrent.{ExecutionContext, Future}

class MaterialSync @Inject()(kingdeePostV2: KingdeePostV2)(implicit ec: ExecutionContext)
  extends Logging {
  private val dcid_lidun = "lidun"
  private val dcid_wuyang = ""

  /**
   *
   * @param mFNumber       编码
   * @param mName          名称
   * @param mSpecification 规格
   * @param mBARCODE       条码
   * @param mFErpClsID     物料属性
   * @param sizeInfo       尺寸
   */
  private case class MaterialSyncInfo(mFNumber: String, mName: String, mSpecification: String, mBARCODE: String, mFErpClsID: String, sizeInfo: MaterialSizeInfo)

  /**
   * weight unit kg, length unit cm *
   *
   * @param grossWeight 毛重
   * @param netWeight   净重
   * @param length      长
   * @param width       宽
   * @param height      高
   * @param volume      体积
   */
  private case class MaterialSizeInfo(grossWeight: Double, netWeight: Double, length: Double, width: Double, height: Double, volume: Double)

  private def toKingdee(src: JsValue): MaterialSyncInfo = {
    val mbase = (src \ "MaterialBase" \ 0).as[JsValue]
    //      "WEIGHTUNITID": { "Number": "kg", },
    val w_percent = UnitChangePercent.to_kg((mbase \ "WEIGHTUNITID" \ "Number").asOpt[String].getOrElse("kg"))
    //      "VOLUMEUNITID": { "Number": "mm", },
    val v_percent = UnitChangePercent.to_cm((mbase \ "VOLUMEUNITID" \ "Number").asOpt[String].getOrElse("mm"))
    val sizeInfo = MaterialSizeInfo(
      //      "GROSSWEIGHT": 1.25,
      grossWeight = w_percent * (mbase \ "GROSSWEIGHT").as[Double],
      //      "NETWEIGHT": 1.23,
      netWeight = w_percent * (mbase \ "NETWEIGHT").as[Double],
      //      "LENGTH": 145.0,
      length = v_percent * (mbase \ "LENGTH").as[Double],
      //      "WIDTH": 110.0,
      width = v_percent * (mbase \ "WIDTH").as[Double],
      //      "HEIGHT": 100.0,
      height = v_percent * (mbase \ "HEIGHT").as[Double],
      //      "VOLUME": 1595000.0,
      volume = v_percent * v_percent * v_percent * (mbase \ "VOLUME").as[Double]
    )
    MaterialSyncInfo(
      // "A0000003" //    src["Number"]
      mFNumber = (src \ "Number").as[String],
      //"测试商品F0000003" //  src["Name"][0]["Value"]
      mName = (src \ "Name" \ 0 \ "Value").as[String],
      //   规格 "" if src["Specification"][0]["Value"] == " " else src["Specification"][0]["Value"],
      mSpecification = (src \ "Specification" \ 0 \ "Value").asOpt[String].getOrElse(""),
      //  条码    src["MaterialBase"][0]["BARCODE"]
      mBARCODE = (mbase \ "BARCODE").asOpt[String].getOrElse(""),
      //  1 外购 2 自制 6 服务  物料属性  src["MaterialBase"][0]["ErpClsID"]
      mFErpClsID = if ((mbase \ "ErpClsID").as[String].equals("6")) "6" else "1",
      sizeInfo = sizeInfo
    )
  }

  /**
   *
   * @param src {"Result": { "Result": src }}
   * @param mid "FMATERIALID"
   * @return
   */
  private def save(src: MaterialSyncInfo, mid: Long = 0): Future[String] = {
    logger.debug(src.toString)
    val is_stock = if (src.mFErpClsID == "6") false else true
    val is_golf = if(is_stock) "W" else "F"
    val FPlanningStrategy = if (is_stock) "1" else "2"
    //  产成品 "CHLB05_SYS"    服务 "CHLB06_SYS"
    val FCategoryID = if (is_stock) "CHLB05_SYS" else "CHLB06_SYS"
    // 批号编码规则
    val FBatchRuleID = if (is_stock) """"FBatchRuleID":{"FNumber":"PHBM001"},""" else ""
    val weightInfo = {
      val gw = src.sizeInfo.grossWeight
      val nw = src.sizeInfo.netWeight
      val l = src.sizeInfo.length
      val w = src.sizeInfo.width
      val h = src.sizeInfo.height
      val v = src.sizeInfo.volume
      val w0 = if (((gw + nw) * 10000).toLong == 0) false else true
      val v0 = if ((v * 1000).toLong == 0) false else true
      if (w0 && v0) {
        s""" ,"FGROSSWEIGHT":$gw,"FNETWEIGHT":$nw,"FLENGTH":$l,"FWIDTH":$w,"FHEIGHT":$h,"FVOLUME":$v """
      } else if (v0) {
        s""" ,"FLENGTH":$l,"FWIDTH":$w,"FHEIGHT":$h,"FVOLUME":$v """
      } else if (w0) {
        s""" ,"FGROSSWEIGHT":$gw,"FNETWEIGHT":$nw """
      } else {
        ""
      }
    }

    //
    val para =
      s"""
         |{
         |    "NeedUpDateFields": [],
         |    "IsAutoSubmitAndAudit": "true",
         |    "Model": {
         |        "FMATERIALID": $mid,
         |        "FCreateOrgId": {"FNumber": "201"},
         |        "FUseOrgId": {"FNumber": "201"},
         |        "FNumber": "${src.mFNumber}",
         |        "FName": "${src.mName}",
         |        "FSpecification": "${src.mSpecification}",
         |        "FMaterialGroup": {"FNumber": "$is_golf"},
         |        "FDSMatchByLot": false,
         |        "FImgStorageType": "A",
         |        "FIsSalseByNet": false,
         |        "SubHeadEntity": {
         |            "FErpClsID": "${src.mFErpClsID}",
         |            "FFeatureItem": "1",
         |            "FCategoryID": {"FNumber": "$FCategoryID"},
         |            "FBaseUnitId": {"FNumber": "Pcs"},
         |            "FBARCODE": "${src.mBARCODE}",
         |            "FVOLUMEUNITID": {"FNUMBER": "cm"},
         |            "FWEIGHTUNITID": {"FNUMBER": "kg"} $weightInfo
         |        },
         |        "SubHeadEntity1": {
         |            "FStoreUnitID": {"FNumber": "Pcs"},
         |            "FUnitConvertDir": "1",
         |            "FIsBatchManage": true,
         |            $FBatchRuleID
         |            "FIsKFPeriod": false,
         |            "FIsExpParToFlot": false,
         |            "FCurrencyId": {"FNumber": "PRE001"},
         |            "FIsSNManage": false,
         |            "FIsSNPRDTracy": false,
         |            "FSNManageType": "1",
         |            "FSNGenerateTime": "1"
         |        },
         |        "SubHeadEntity2": {
         |            "FSaleUnitId": {"FNumber": "Pcs"},
         |            "FSalePriceUnitId": {"FNumber": "Pcs"}
         |        },
         |        "SubHeadEntity3": {
         |            "FPurchaseUnitId": {"FNumber": "Pcs"},
         |            "FPurchasePriceUnitId": {"FNumber": "Pcs"},
         |            "FPurchaseOrgId": {"FNumber": "201"},
         |            "FQuotaType": "1"
         |        },
         |        "SubHeadEntity4": {
         |            "FPlanningStrategy": "$FPlanningStrategy",
         |            "FFixLeadTimeType": "1",
         |            "FVarLeadTimeType": "1",
         |            "FCheckLeadTimeType": "1",
         |            "FOrderIntervalTimeType": "3",
         |            "FReserveType": "1",
         |            "FPlanOffsetTimeType": "1"
         |        },
         |        "SubHeadEntity5": {
         |            "FProduceUnitId": {"FNumber": "Pcs"},
         |            "FProduceBillType": {"FNUMBER": "SCDD03_SYS"},
         |            "FOrgTrustBillType": {"FNUMBER": "SCDD06_SYS"},
         |            "FIsSNCarryToParent": false,
         |            "FIsProductLine": false,
         |            "FBOMUnitId": {"FNumber": "Pcs"},
         |            "FIsMainPrd": $is_stock,
         |            "FIsCoby": false,
         |            "FIsECN": false,
         |            "FMinIssueUnitId": {"FNUMBER": "Pcs"},
         |            "FStandHourUnitId": "3600",
         |            "FBackFlushType": "1",
         |            "FIsEnableSchedule": false
         |        },
         |        "SubHeadEntity7": {
         |            "FSubconUnitId": {"FNumber": "Pcs"},
         |            "FSubconPriceUnitId": {"FNumber": "Pcs"},
         |            "FSubBillType": {"FNUMBER": "WWDD01_SYS"}
         |        },
         |        "FEntityInvPty": [
         |            {
         |                "FInvPtyId": {"FNumber": "01"},
         |                "FIsEnable": true,
         |                "FIsAffectPrice": false,
         |                "FIsAffectPlan": false,
         |                "FIsAffectCost": false
         |            },
         |            {
         |                "FInvPtyId": {"FNumber": "02"},
         |                "FIsEnable": true,
         |                "FIsAffectPrice": false,
         |                "FIsAffectPlan": false,
         |                "FIsAffectCost": false
         |            },
         |            {
         |                "FInvPtyId": {"FNumber": "03"},
         |                "FIsEnable": false,
         |                "FIsAffectPrice": false,
         |                "FIsAffectPlan": false,
         |                "FIsAffectCost": false
         |            },
         |            {
         |                "FInvPtyId": {"FNumber": "04"},
         |                "FIsEnable": true,
         |                "FIsAffectPrice": false,
         |                "FIsAffectPlan": false,
         |                "FIsAffectCost": false
         |            },
         |            {
         |                "FInvPtyId": {"FNumber": "06"},
         |                "FIsEnable": false,
         |                "FIsAffectPrice": false,
         |                "FIsAffectPlan": false,
         |                "FIsAffectCost": false
         |            }
         |        ]
         |    }
         |}
         |""".stripMargin.replace(" ", "")
    kingdeePostV2.setKdAppConfig(dcid_lidun).save("BD_MATERIAL", Json.parse(para))
  }

  private def view(number: String): Future[String] = {
    kingdeePostV2.setKdAppConfig(dcid_wuyang).view("BD_MATERIAL", s"{\"Number\": \"$number\"}")
  }


  private def list(number: String): Future[(Long, String, String)] = {
    val para = Json.obj(
      "FormId" -> "BD_MATERIAL",
      "FieldKeys" -> "FMATERIALID,FDocumentStatus,FForbidStatus,FName,FNumber",
      "FilterString" -> s"FNumber='$number'",
      "OrderString" -> "",
      "TopRowCount" -> 0,
      "StartRow" -> 0,
      "Limit" -> 2000,
      "SubSystemId" -> "")
    kingdeePostV2.setKdAppConfig(dcid_lidun).executeBillQuery(para).map {
      res => {
        logger.debug(s"list($number) => " + res)
        if (res.startsWith("[[")) {
          val arr = Json.parse(res).as[Array[JsArray]].head
          ((arr \ 0).as[Long], (arr \ 1).as[String], (arr \ 2).as[String])
        } else {
          (0, "", "")
        }
      }
    }
  }

  def operation(code: String): Future[String] = {
    view(code).flatMap { res =>
      try {
        val js = Json.parse(res)
        val src = (js \ "Result" \ "Result").asOpt[JsValue]
        if (src.isEmpty) Future(s"$code:not find; ")
        else {
          list(code).flatMap {
            m => {
              if (m._3.equals("A")) {
                // ExcuteOperation "BD_MATERIAL","Enable","{"CreateOrgId":0,"Numbers":[],"Ids":"","IgnoreInterationFlag":""}"
                kingdeePostV2
                  .setKdAppConfig(dcid_lidun)
                  .excuteOperation("BD_MATERIAL", "Enable", s"{\"Numbers\":\"$code\"}")
              }
              if (m._2.equals("C")) {
                kingdeePostV2
                  .setKdAppConfig(dcid_lidun)
                  .unAudit("BD_MATERIAL", s"{\"Numbers\":\"$code\"}")
              }
              save(toKingdee(src.get), m._1).map {
                res => {
                  // {"Result":{"ResponseStatus":{
                  // "IsSuccess":true,
                  // "Errors":[],
                  // "SuccessEntitys":[{"Id":199501,"Number":"CGTL2012305000385","DIndex":0}],
                  // "SuccessMessages":[],"MsgCode":0}}}
                  val r = Json.parse(res)
                  if ((r \ "Result" \ "ResponseStatus" \ "IsSuccess").as[Boolean]) {
                    s"$code:Ok; "
                  } else {
                    logger.warn(s"Number($code) errors:" + (r \ "Result" \ "ResponseStatus" \ "Errors").as[JsArray].toString())
                    s"$code:error-" + (r \ "Result" \ "ResponseStatus" \ "MsgCode").asOpt[Int].toString + "; "
                  }
                }
              }
            }
          }
        }
      } catch {
        case e: Exception => {
          logger.debug("", e)
          Future(res)
        }
      }
    }
  }

}
